#pragma once

#include "host.h"

#ifdef WIN32
#include <windows.h>
#else
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#endif

typedef int OS_Error;

namespace host {
    class OSSocket
    {
    public:
        //Send
        //Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
        virtual OSErr Send(const void* inBuffer, size_t inLength, size_t* outLengthSent) = 0;

        //Read
        //Returns: QTSS_FileNotOpen, QTSS_NoErr, or POSIX errorcode.
        virtual OSErr Recv(void *buffer, size_t inLengthMax, size_t*recvLen) = 0;

        OSErr Close();

        //If the socket is bound, you may find out to which addr it is bound
        UInt32  GetLocalAddr() { return ntohl(m_tSelfAddr.sin_addr.s_addr); }
        UInt16  GetLocalPort() { return ntohs(m_tSelfAddr.sin_port); }

    protected:
        OSErr Open(int theType);

        //address information (available if bound)
        //these are always stored in network order. Conver
        struct sockaddr_in  m_tSelfAddr;
        struct sockaddr_in  m_tPeerAddr;


#ifdef _WIN32
        SOCKET  hFileDesc;
#else
        int     hFileDesc;
#endif
    };

    class TCPSocket : public OSSocket
    {
    public:
        virtual ~TCPSocket() {}

        //Open
        OSErr Open() { return OSSocket::Open(SOCK_STREAM); }

        OSErr Connect(UInt32 inRemoteAddr, UInt16 inRemotePort);

        virtual OSErr Send(const void* inBuffer, size_t inLength, size_t* outLengthSent);

        virtual OSErr Recv(void *buffer, size_t inLengthMax, size_t*recvLen);

        //virtual OSErr Close();
    };



    class UDPSocket : public OSSocket
    {
    public:
        ~UDPSocket() {}

        //Open
        OSErr Open() { return OSSocket::Open(SOCK_DGRAM); }

        //virtual OSErr Close();

        OSErr Bind(UInt32 inLocalAddr, UInt16 inLocalPort);
        //OSErr Connect(UInt32 inRemoteAddr, UInt16 inRemotePort);

        OSErr SendTo(UInt32 inRemoteAddr, UInt16 inRemotePort, void* inBuffer, size_t inLength);

        OSErr RecvFrom(UInt32* outRemoteAddr, UInt16* outRemotePort, void* ioBuffer, size_t inBufLen, size_t* outRecvLen);

        virtual OSErr Send(const void* inBuffer, size_t inLength, size_t* outLengthSent);

        virtual OSErr Recv(void* buffer, size_t inLengthMax, size_t* recvLen);
    };

};
